package main

import (
	"bytes"
	"database/sql"
	"errors"
	"fmt"
	"log"
	"os"

	_ "image/png" // register PNG decoder

	_ "github.com/mattn/go-sqlite3"
)
type ANODE struct{
	Parentid int
	Title    string
	b bytes.Buffer//Picicon  *[]byte  // blob,
	//Lenpic   int   //blob bytes length
	Showorder int
}
//如果有就打开，如果没有则新建
func opendb(dbfilepathname string) *sql.DB {
	db, err := sql.Open("sqlite3", dbfilepathname) //"./ctb.db"
	errlog(err)
	db.SetMaxOpenConns(2)
	return db
	//defer db.Close()
	//When you get a database is locked. Please use the following options.
	//Add to DSN: cache=shared
	//db, err := sql.Open("sqlite3", "file:locked.sqlite?cache=shared")
}
//mkcontent   #记事内容，非文本部分以key引用blobjson中的数据
//picjson    #记录文本中插入的非文本数据
func createtable(db *sql.DB)  {
	sqlStmt := `
	create table if not exists notes (id integer not null primary key AUTOINCREMENT, 
                        title      text ,
                        subtitle   text,
                        keys       text,
	                    mkcontent  text, 
	                    picjson   blob  
                       );
	delete from notes;
	`
	_, err := db.Exec(sqlStmt)
	if err != nil {		log.Printf("%q: %s\n", err, sqlStmt)	}
	// 主菜单，即左导航栏tree
	sqlStmt = `CREATE TABLE  if not exists "mainmenu" (
				    "id" INTEGER NOT NULL,
					"parentid" INTEGER,
					"title"     TEXT,
					"picicon"   blob,
					"is_delete" integer,
					"showorder" integer,
					PRIMARY KEY ("id")
				);`
	_, err = db.Exec(sqlStmt)
	if err != nil {		log.Printf("%q: %s\n", err, sqlStmt)	}
}

func insert2mu(db *sql.DB, node ANODE)  {
	tx, err := db.Begin()                                                      ;errlog(err)
	stmt, err := tx.Prepare("insert into mainmenu(parentid,title,picicon,showorder) values(?,?,?,?)")    ;errlog(err)
	defer stmt.Close()

	_, err = stmt.Exec(node.Parentid,node.Title,node.b.Bytes(),node.Showorder)
	errlog(err)
	tx.Commit()
}
//写入blog 字段数据，insert，update
//read image file to bytes.Buffer
func readimgfrombuf(srcbuf *bytes.Buffer,filename string,b *bytes.Buffer) *bytes.Buffer   {

	if srcbuf==nil{
		if filename != "" {
			f, err := os.OpenFile(filename,os.O_RDONLY,0755)
			errlog(err)
			defer f.Close()

			fi,err:=os.Lstat(filename)
			filelen:=fi.Size();errlog(err)
			b.Grow(int(filelen))
			//fmt.Println(filename,filelen,b.Len())
			b.ReadFrom(f)

			return b
		}
		return nil
	}
	return  srcbuf

}

func selectfromdb(db *sql.DB){

	rows, err := db.Query("select id, name from foo where name like '测试%'")      ;errlog(err)
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		err = rows.Scan(&id, &name)    ;errlog(err)
		fmt.Println(id, name)
	}
	err = rows.Err()                   ;errlog(err)

	stmt, err := db.Prepare("select name from foo where id = ?")    ;errlog(err)
	defer stmt.Close()
	var name string
	err = stmt.QueryRow("3").Scan(&name)    ;errlog(err)
	fmt.Println(name)

	_, err = db.Exec("delete from foo")    ;errlog(err)

	_, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')")    ;errlog(err)

	rows, err = db.Query("select id, name from foo")   	;errlog(err)
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		err = rows.Scan(&id, &name)     ;	errlog(err)
		fmt.Println(id, name)
	}
	err = rows.Err()
	errlog(err)

}

/// 下面这个函数实现如何从error中恢复
func simulate_err()  {
	defer func() {
		if p := recover(); p != nil {
			err := fmt.Errorf("internal error: %v", p)
			errprint(err)
		}
	}()
	// your code ......
	// 模拟一个错误，触发之 。被匿名函数捕获：从error 中恢复，并打印
	var EOF = errors.New("EOF")
	panic(EOF )
}
func errlog(e error,v ...interface{})  {
	if e != nil{
		log.Fatal(e,">>",v)
	}
}
func errprint(e error,v ...interface{})  {
	if e != nil{
		fmt.Println(e,">>",v)
	}
}